from config import *
from config import make_df_ECB
%matplotlib inline
La legge di Okun
Introduzione
All’inizio degli anni ’60, la crescita economica e la riduzione della disoccupazione erano temi centrali per gli economisti americani. Arthur M. Okun si specializzò nello studio del prodotto potenziale, ovvero il livello di output raggiungibile in condizioni di disoccupazione ottimale (all’epoca stimata intorno al 4%) e di una domanda sufficiente ad assorbire l’offerta disponibile.
Dal punto di vista pratico, era fondamentale quantificare l’impatto di una variazione della disoccupazione sulla produzione. Ad esempio, una riduzione del tasso di disoccupazione dal 6% al 4,5% avrebbe avvicinato il prodotto al suo livello potenziale, riducendo il “gap” tra output effettivo e potenziale. Al contrario, un aumento della disoccupazione avrebbe avuto l’effetto opposto.
L’obiettivo di Okun era individuare una relazione quantitativa tra il prodotto nazionale lordo (PNL) e il tasso di disoccupazione. In questa sezione analizzeremo le due metodologie con cui Okun ha stimato tale relazione.
I. Differenze percentuali
In questo primo esercizio, viene utilizzato un modello di regressione lineare con intercetta, dove le variazioni nel tasso di disoccupazione Y vengono regredite sulle variazioni percentuali di PNL X. Tutti i dati sono rilevati trimestralmente. Le serie utilizzate sono: - https://fred.stlouisfed.org/series/UNRATE per il tasso di disoccupazione - https://www.nber.org/research/data/american-business-cycle-continuity-and-change-historic-data-tables per il PNL
# Carica il dataset contenente il tasso di disoccupazione da un file CSV
= pd.read_csv('UNRATE_OKUN.csv')
unemp
# Converte la colonna delle date in formato datetime per una gestione più efficace delle serie temporali
'observation_date'] = pd.to_datetime(unemp['observation_date'], format='%Y-%m-%d')
unemp[
# Imposta la colonna delle date come indice del DataFrame per lavorare con serie temporali
= unemp.set_index('observation_date')
unemp
# Raggruppa i dati per trimestre calcolando la media del tasso di disoccupazione per ogni periodo
= unemp.groupby(pd.Grouper(freq='Q'))['UNRATE'].mean().to_frame()
unemp
# Converte l'indice in un PeriodIndex con frequenza trimestrale per una gestione più accurata delle serie storiche
= pd.PeriodIndex(unemp.index, freq='Q')
unemp.index
# Calcola la variazione trimestrale del tasso di disoccupazione
'change_unemp'] = unemp['UNRATE'].diff()
unemp[
# Rimuove eventuali valori NaN generati dalla differenziazione
= unemp.dropna()
unemp
# Filtra i dati fino al quarto trimestre del 1960 per allinearsi al periodo di interesse
= unemp[unemp.index <= '1960Q4']
unemp
# Visualizza le prime righe del DataFrame risultante
unemp.head()
UNRATE | change_unemp | |
---|---|---|
observation_date | ||
1948Q2 | 3.666667 | -0.066667 |
1948Q3 | 3.766667 | 0.100000 |
1948Q4 | 3.833333 | 0.066667 |
1949Q1 | 4.666667 | 0.833333 |
1949Q2 | 5.866667 | 1.200000 |
# Carica il dataset contenente il prodotto nazionale lordo (PNL) da un file CSV
= pd.read_csv('abcq.csv')
gnp
# Crea una nuova colonna per la data, combinando l'anno e il trimestre
'observation_date'] = gnp['year'].astype(str) + 'Q' + gnp['quarter'].astype(str)
gnp[
# Imposta la colonna 'observation_date' come indice del DataFrame
= gnp.set_index('observation_date')
gnp
# Converte l'indice in un PeriodIndex con frequenza trimestrale per una gestione più accurata delle serie storiche
= pd.PeriodIndex(gnp.index, freq='Q')
gnp.index
# Seleziona solo la colonna 'GNP' e la converte in un DataFrame
= gnp['GNP'].to_frame()
gnp
# Calcola la variazione percentuale trimestrale del prodotto nazionale lordo
'pct_change_gnp'] = gnp['GNP'].pct_change() * 100
gnp[
# Rimuove eventuali valori NaN generati dalla differenziazione
= gnp.dropna()
gnp
# Filtra i dati per mantenere solo il periodo tra il secondo trimestre del 1948 e il quarto trimestre del 1960
= gnp[(gnp.index <= '1960Q4') & (gnp.index >= '1948Q2')]
gnp
# Visualizza le prime righe del DataFrame risultante
gnp.head()
GNP | pct_change_gnp | |
---|---|---|
observation_date | ||
1948Q2 | 257.5 | 3.000000 |
1948Q3 | 264.5 | 2.718447 |
1948Q4 | 265.9 | 0.529301 |
1949Q1 | 260.5 | -2.030839 |
1949Q2 | 257.0 | -1.343570 |
# Unisce i DataFrame 'unemp' e 'gnp' utilizzando l'indice come chiave di unione
= pd.merge(unemp, gnp, right_index=True, left_index=True)
df
# Definisce la variabile indipendente X (le variazioni percentuali del PNL)
= df['pct_change_gnp']
X
# Definisce la variabile dipendente Y (le variazioni del tasso di disoccupazione)
= df['change_unemp']
Y
# Aggiunge un termine costante al modello di regressione per tener conto dell'intercetta
= sm.add_constant(X)
X
# Crea il modello di regressione lineare (OLS) con Y come dipendente e X come indipendente
= sm.OLS(Y, X)
model
# Adatta il modello ai dati
= model.fit()
results
# Stampa i risultati della regressione
print(results.summary())
OLS Regression Results
==============================================================================
Dep. Variable: change_unemp R-squared: 0.631
Model: OLS Adj. R-squared: 0.623
Method: Least Squares F-statistic: 83.74
Date: Fri, 21 Mar 2025 Prob (F-statistic): 3.51e-12
Time: 18:54:20 Log-Likelihood: -19.032
No. Observations: 51 AIC: 42.06
Df Residuals: 49 BIC: 45.93
Df Model: 1
Covariance Type: nonrobust
==================================================================================
coef std err t P>|t| [0.025 0.975]
----------------------------------------------------------------------------------
const 0.4238 0.065 6.546 0.000 0.294 0.554
pct_change_gnp -0.2669 0.029 -9.151 0.000 -0.325 -0.208
==============================================================================
Omnibus: 6.492 Durbin-Watson: 1.585
Prob(Omnibus): 0.039 Jarque-Bera (JB): 5.400
Skew: 0.713 Prob(JB): 0.0672
Kurtosis: 3.714 Cond. No. 3.12
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
L’interpretazione dei coefficienti è immediata: tenendo fisso il PNL il tasso di disoccupazione aumenterà di .42 punti da un trimestre all’altro, in quanto la crescita della forza lavoro e i processi tecnologici spingeranno in basso il rapporto occupati/forza lavoro attiva. Per ogni aumento di 1 punto percentuale del PNL, il tasso di disoccupazione diminuirà di .27 punti. Di converso, un aumento del tasso di disoccupazione di 1 punto percentuale comporterà una riduzione del PNL del 3.7%.
Si può notare che i valori ottenuti non sono dissimili da quelli dell’articolo originale, che riporta una approssimazione: \[
Y = .3 - .3X
\] In questi casi, il metodo di rilevazione dei dati ed eventuali manipolazioni successive possono essere responsabili di leggere variazioni nei coefficienti.
# Calcola le previsioni per la variazione del tasso di disoccupazione usando il modello di regressione
'pred_unemp_change'] = results.predict(X)
df[
# Ordina i dati in base alla variazione percentuale del PNL (X)
= df.sort_values(by='pct_change_gnp')
sorted_data
# Crea una figura con un solo subplot
= plt.subplots(1, 1)
fig, ax
# Aggiunge una linea orizzontale a y=0 per facilitare la lettura del grafico
=0, color='silver', linewidth=2)
ax.axhline(y
# Crea un grafico a dispersione per visualizzare le osservazioni reali (variabile dipendente vs variabile indipendente)
'pct_change_gnp'], df['change_unemp'], alpha=0.7, label="Osservazioni", color=bmh_colors[0])
ax.scatter(df[
# Aggiunge la linea di regressione (legge di Okun) sul grafico
'pct_change_gnp'], sorted_data['pred_unemp_change'],
ax.plot(sorted_data[=bmh_colors[1], label="Legge Di Okun")
color
# Imposta il titolo del grafico e lo allinea a sinistra
f"US, 1948-1960", loc='left')
ax.set_title(
# Imposta le etichette degli assi
'Variazione Del PNL')
ax.set_xlabel('Variazione Del Tasso Di Disoccupazione')
ax.set_ylabel(
# Aggiunge la griglia al grafico per facilitare la lettura
True)
ax.grid(
# Aggiunge la legenda al grafico
ax.legend()
# Ottimizza il layout del grafico per una visualizzazione migliore
plt.tight_layout()
II. Elasticità
Questo metodo è molto importante dal punto di vista pratico, in quanto consente di associare dei coefficienti ai livelli di PNL e tasso di occupazione, piuttosto che alle loro variazioni percentuali. Questo servirà in seguito per stimare il PNL potenziale. In particolare, si ipotizza che:
ci sia elesticità costante (\(a\)) fra il rapporto tra prodotto osservato (\(A\)-actual) e potenziale (\(P\)) ed il rapporto fra tasso di occupazione (\(N\)) e tasso di occupazione potenziale (\(N_F\)). In simboli: \(\frac{N}{N_F} = \left( \frac{A}{P} \right)^a\)
il prodotto potenziale cresca ad un tasso costante \(r\) in funzione del tempo: \(P-t = P_0 e^{rt}\)
Il risultato restituisce l’equazione del modello, i cui parametri verranno stimati tramite OLS: \[\ln N_t = \ln \frac{N_F}{P_0^a} + a \ln A_t - (ar)t\]
# Calcola il tasso di occupazione sottraendo il tasso di disoccupazione da 100
'emprate'] = 100 - df['UNRATE']
df[
# Calcola il logaritmo naturale del tasso di occupazione
'logN'] = np.log(df['emprate'])
df[
# Calcola il logaritmo naturale del Prodotto Nazionale Lordo (PNL)
'logA'] = np.log(df['GNP'])
df[
# Crea una variabile trend che va da 1 fino al numero di osservazioni (usata per catturare l'effetto di trend nel modello)
'trend'] = range(1, 1+len(df))
df[
# Mostra le prime righe del DataFrame risultante per una rapida verifica
df.head()
UNRATE | change_unemp | GNP | pct_change_gnp | pred_unemp_change | emprate | logN | logA | trend | |
---|---|---|---|---|---|---|---|---|---|
observation_date | |||||||||
1948Q2 | 3.666667 | -0.066667 | 257.5 | 3.000000 | -0.376806 | 96.333333 | 4.567814 | 5.551020 | 1 |
1948Q3 | 3.766667 | 0.100000 | 264.5 | 2.718447 | -0.301666 | 96.233333 | 4.566776 | 5.577841 | 2 |
1948Q4 | 3.833333 | 0.066667 | 265.9 | 0.529301 | 0.282564 | 96.166667 | 4.566083 | 5.583120 | 3 |
1949Q1 | 4.666667 | 0.833333 | 260.5 | -2.030839 | 0.965804 | 95.333333 | 4.557380 | 5.562603 | 4 |
1949Q2 | 5.866667 | 1.200000 | 257.0 | -1.343570 | 0.782388 | 94.133333 | 4.544712 | 5.549076 | 5 |
# Definisce la variabile dipendente Y (logaritmo naturale del tasso di occupazione)
= df['logN']
Y
# Definisce la matrice delle variabili indipendenti X (logaritmo del PNL e trend)
= df[['logA', 'trend']]
X
# Aggiunge una costante a X per includere l'intercetta nel modello
= sm.add_constant(X)
X
# Crea un modello di regressione lineare ordinario (OLS) con Y come variabile dipendente e X come variabili indipendenti
= sm.OLS(Y,X)
model
# Calcola i risultati del modello
= model.fit()
results
# Stampa il sommario dei risultati della regressione
print(results.summary())
OLS Regression Results
==============================================================================
Dep. Variable: logN R-squared: 0.854
Model: OLS Adj. R-squared: 0.848
Method: Least Squares F-statistic: 140.6
Date: Fri, 21 Mar 2025 Prob (F-statistic): 8.53e-21
Time: 18:54:21 Log-Likelihood: 196.88
No. Observations: 51 AIC: -387.8
Df Residuals: 48 BIC: -382.0
Df Model: 2
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 2.9807 0.101 29.463 0.000 2.777 3.184
logA 0.2853 0.018 15.662 0.000 0.249 0.322
trend -0.0043 0.000 -16.516 0.000 -0.005 -0.004
==============================================================================
Omnibus: 3.874 Durbin-Watson: 0.521
Prob(Omnibus): 0.144 Jarque-Bera (JB): 3.453
Skew: -0.636 Prob(JB): 0.178
Kurtosis: 2.930 Cond. No. 4.24e+03
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 4.24e+03. This might indicate that there are
strong multicollinearity or other numerical problems.
Dove il coefficiente di logA è l’elasticità dell’output al tasso di occupazione; il coefficiente del tempo è, per definizione, il prodotto tra il coefficiente di logA e il tasso di crescita costante del prodotto potenziale; l’intercetta restituisce il benchmark \(P_0\) per ogni livello di \(N_F\), che verrà preso pari a 96.
Iterate regressioni hanno portato Okun al seguente risultato: \[
P = A \left( 1+ .032 \left( U-4 \right) \right)
\]
from mpl_toolkits.mplot3d import Axes3D
# Crea una nuova figura per il grafico 3D con dimensioni personalizzate
= plt.figure(figsize=(10, 7))
fig
# Aggiunge un subplot 3D alla figura
= fig.add_subplot(111, projection='3d')
ax
# Crea un grafico scatter 3D con logA, trend e logN, etichettato come 'Osservazioni'
'logA'], df['trend'], df['logN'], label='Osservazioni', alpha=0.7)
ax.scatter(df[
# Definisce i valori di intervallo per logA e trend (in modo da poter creare una superficie)
= np.linspace(df['logA'].min(), df['logA'].max(), 20)
logA_range = np.linspace(df['trend'].min(), df['trend'].max(), 20)
trend_range
# Crea una griglia di valori per logA e trend
= np.meshgrid(logA_range, trend_range)
logA_grid, trend_grid
# Calcola i valori adattati della superficie utilizzando i parametri stimati dal modello di regressione
= results.params['const'] + results.params['logA'] * logA_grid + results.params['trend'] * trend_grid
fitted_values
# Aggiunge la superficie al grafico 3D, colorandola con un colore specifico e un'alpha di trasparenza
=bmh_colors[1], alpha=0.5)
ax.plot_surface(logA_grid, trend_grid, fitted_values, color
# Imposta le etichette degli assi
'logA')
ax.set_xlabel('Trend')
ax.set_ylabel('logN')
ax.set_zlabel(
# Imposta il titolo del grafico
'Legge Di Okun, livelli')
ax.set_title(
# Modifica l'angolazione della visualizzazione per rendere più chiara la superficie
=20, azim=45)
ax.view_init(elev
# Aggiunge la legenda al grafico
plt.legend()
# Mostra il grafico
plt.show()
# Calcola il PNL potenziale utilizzando la formula di Okun (assumendo un tasso di disoccupazione ottimale del 4%)
'potential_gnp'] = df['GNP']*(1+.032*(df['UNRATE']-4))
df[
# Crea un grafico con un subplot
= plt.subplots(1,1)
fig, ax
# Filtra i dati dal primo trimestre del 1954 e traccia il PNL osservato
>='1954Q1']['GNP'].plot(label='PNL', ax=ax)
df[df.index
# Filtra i dati dal primo trimestre del 1954 e traccia il PNL potenziale calcolato
>='1954Q1']['potential_gnp'].plot(label='PNL potenziale', ax=ax)
df[df.index
# Aggiunge etichette agli assi
'PNL (in miliardi di dollari)')
plt.ylabel('Trimestre')
plt.xlabel(
# Aggiunge il titolo al grafico, posizionandolo a sinistra
'Calcolo Del PNL Potenziale Secondo Okun', loc='left')
plt.title(
# Mostra la legenda per distinguere le due linee
plt.legend()
# Regola la disposizione del layout per ottimizzare lo spazio
plt.tight_layout()
E oggi?
# Funzione per estrarre i dati dal datawarehouse della BCE
def make_df_ECB(key, obs_name):
"""Estrae i dati dal datawarehouse della BCE"""
= 'https://sdw-wsrest.ecb.europa.eu/service/data/' # URL di base per il servizio web della BCE
url_ = '?format=csvdata' # Impostazione del formato dei dati in CSV
format_ = pd.read_csv(url_+key+format_) # Legge i dati CSV dal servizio web BCE usando la chiave
df = df[['TIME_PERIOD', 'OBS_VALUE']] # Seleziona le colonne di interesse (periodo e valore osservato)
df 'TIME_PERIOD'] = pd.to_datetime(df['TIME_PERIOD']) # Converte il periodo in formato datetime
df[= df.set_index('TIME_PERIOD') # Imposta il periodo come indice del dataframe
df = [obs_name] # Rinomina la colonna con il nome della variabile
df.columns return df
# Chiave per il tasso di disoccupazione
= 'LFSI/Q.I9.S.UNEHRT.TOTAL0.15_74.T' # Codice identificativo del tasso di disoccupazione
unemp_rate_key = make_df_ECB(unemp_rate_key, 'unemp') # Ottieni i dati dal database ECB
unemp 'change_unemp'] = unemp['unemp'].diff() # Calcola la variazione del tasso di disoccupazione
unemp[
# Chiave per il PIL (GDP)
= 'MNA/Q.Y.I9.W2.S1.S1.B.B1GQ._Z._Z._Z.EUR.LR.N' # Codice identificativo del PIL
gdp_key = make_df_ECB(gdp_key, 'gdp') # Ottieni i dati dal database ECB
gdp 'pct_change_gdp'] = gdp['gdp'].pct_change()*100 # Calcola la variazione percentuale del PIL
gdp[
# Unisci i dati del tasso di disoccupazione e del PIL
= pd.merge(unemp, gdp, right_index=True, left_index=True)
df = df.dropna() # Rimuove le righe con valori NaN
df
# Mostra le prime righe del dataframe risultante
df.head()
unemp | change_unemp | gdp | pct_change_gdp | |
---|---|---|---|---|
TIME_PERIOD | ||||
2000-04-01 | 9.128157 | -0.223128 | 2.433026e+06 | 0.896372 |
2000-07-01 | 8.982247 | -0.145910 | 2.449339e+06 | 0.670484 |
2000-10-01 | 8.751499 | -0.230748 | 2.460466e+06 | 0.454298 |
2001-01-01 | 8.532471 | -0.219028 | 2.487753e+06 | 1.109010 |
2001-04-01 | 8.472304 | -0.060167 | 2.489155e+06 | 0.056341 |
# Definizione delle variabili indipendente (X) e dipendente (Y)
= df['pct_change_gdp'] # Variabile indipendente: variazione percentuale del PIL
X = df['change_unemp'] # Variabile dipendente: variazione del tasso di disoccupazione
Y
# Aggiunta dell'intercetta (costante) al modello
= sm.add_constant(X) # Aggiunge una colonna di 1 alla variabile indipendente per includere l'intercetta
X
# Creazione del modello di regressione lineare (OLS)
= sm.OLS(Y, X) # OLS: Ordinary Least Squares (minimi quadrati ordinari)
model
# Fitting del modello (stima dei parametri)
= model.fit() # Calcola i risultati del modello di regressione
results
# Stampa del sommario dei risultati
print(results.summary()) # Visualizza un riepilogo completo dei risultati della regressione
OLS Regression Results
==============================================================================
Dep. Variable: change_unemp R-squared: 0.006
Model: OLS Adj. R-squared: -0.005
Method: Least Squares F-statistic: 0.5490
Date: Fri, 21 Mar 2025 Prob (F-statistic): 0.460
Time: 18:54:22 Log-Likelihood: 2.0828
No. Observations: 99 AIC: -0.1656
Df Residuals: 97 BIC: 5.025
Df Model: 1
Covariance Type: nonrobust
==================================================================================
coef std err t P>|t| [0.025 0.975]
----------------------------------------------------------------------------------
const -0.0286 0.024 -1.170 0.245 -0.077 0.020
pct_change_gdp -0.0101 0.014 -0.741 0.460 -0.037 0.017
==============================================================================
Omnibus: 42.392 Durbin-Watson: 0.743
Prob(Omnibus): 0.000 Jarque-Bera (JB): 109.819
Skew: 1.560 Prob(JB): 1.42e-24
Kurtosis: 7.110 Cond. No. 1.84
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
Il modello non passa il test di zero-slopes, e nessun coefficiente è significativo. Il modello mostra autocorrelazione positiva (il limite inferiore di DW è intorno a 1.5). come si può constatare dal seguente grafico, la relazione tra variazione nel tasso di disoccupazione e variazione percentuale del PIL è molto debole in Europa, nel periodo considerato.
# Calcolo delle previsioni della variazione del tasso di disoccupazione
'pred_unemp_change'] = results.predict(X)
df[
# Ordinamento dei dati per la variabile indipendente (PIL)
= df.sort_values(by='pct_change_gdp')
sorted_data
# Creazione della figura e dell'asse per il grafico
= plt.subplots(1, 1)
fig, ax
# Aggiunta di una linea orizzontale a y=0
=0, color='silver', linewidth=2)
ax.axhline(y
# Creazione del grafico a dispersione (scatter plot) per le osservazioni effettive
'pct_change_gdp'], df['change_unemp'], alpha=0.7, label="Osservazioni", color=bmh_colors[0])
ax.scatter(df[
# Aggiunta della retta di regressione (Legge di Okun)
'pct_change_gdp'], sorted_data['pred_unemp_change'],
ax.plot(sorted_data[=bmh_colors[1], label="Legge Di Okun")
color
# Titolo e etichette degli assi
f"EU, 2000-2024", loc='left')
ax.set_title('Variazione Del PIL')
ax.set_xlabel('Variazione Del Tasso Di Disoccupazione')
ax.set_ylabel(
# Aggiunta di una griglia al grafico
True)
ax.grid(
# Aggiunta della legenda
ax.legend()
# Ottimizzazione della disposizione del grafico
plt.tight_layout()
Come esercizio, ho replicato il modello aggiungendo i lag di GDP e disoccupazione (come suggerito dal test di DW) - il modello ora riporta un elevato \(R^2\) e coefficienti significativi, tuttavia ha perso il sapore caratteristico dell’originale curva di Okun.
# Creazione delle variabili laggate per la variazione del PIL e per la disoccupazione
'pct_change_gdp_lag1'] = df['pct_change_gdp'].shift(1)
df['unemp_lag1'] = df['change_unemp'].shift(1)
df[
# Rimozione dei valori nulli generati dalla creazione dei lag
= df.dropna()
df
# Creazione delle variabili indipendenti (incluso il termine costante)
= df[['pct_change_gdp', 'pct_change_gdp_lag1', 'unemp_lag1']]
X = sm.add_constant(X)
X
# Variabile dipendente (cambio del tasso di disoccupazione)
= df['change_unemp']
Y
# Creazione del modello di regressione dinamica con stima robusta degli errori (HAC)
= sm.OLS(Y, X).fit(cov_type='HAC', cov_kwds={'maxlags': 4})
model_dyn
# Visualizzazione dei risultati del modello
print(model_dyn.summary())
OLS Regression Results
==============================================================================
Dep. Variable: change_unemp R-squared: 0.760
Model: OLS Adj. R-squared: 0.752
Method: Least Squares F-statistic: 272.3
Date: Fri, 21 Mar 2025 Prob (F-statistic): 3.23e-46
Time: 18:54:22 Log-Likelihood: 71.457
No. Observations: 98 AIC: -134.9
Df Residuals: 94 BIC: -124.6
Df Model: 3
Covariance Type: HAC
=======================================================================================
coef std err z P>|z| [0.025 0.975]
---------------------------------------------------------------------------------------
const 0.0219 0.015 1.476 0.140 -0.007 0.051
pct_change_gdp -0.0260 0.012 -2.166 0.030 -0.050 -0.002
pct_change_gdp_lag1 -0.0766 0.005 -16.759 0.000 -0.086 -0.068
unemp_lag1 0.6233 0.042 14.905 0.000 0.541 0.705
==============================================================================
Omnibus: 5.478 Durbin-Watson: 2.021
Prob(Omnibus): 0.065 Jarque-Bera (JB): 6.170
Skew: 0.289 Prob(JB): 0.0457
Kurtosis: 4.085 Cond. No. 8.21
==============================================================================
Notes:
[1] Standard Errors are heteroscedasticity and autocorrelation robust (HAC) using 4 lags and without small sample correction
# Previsione dei cambiamenti nel tasso di disoccupazione usando il modello dinamico
'pred_unemp_change_2'] = model_dyn.predict(X)
df[
# Ordinamento dei dati in base alla variazione del PIL
= df.sort_values(by='pct_change_gdp')
sorted_data
# Creazione del grafico
= plt.subplots(1, 1)
fig, ax
# Aggiunta della linea orizzontale per il valore zero
=0, color='silver', linewidth=2)
ax.axhline(y
# Creazione dello scatter plot per le osservazioni
'pct_change_gdp'], df['change_unemp'], alpha=0.7, label="Osservazioni", color=bmh_colors[0])
ax.scatter(df[
# Creazione della linea della Legge di Okun basata sulle previsioni
'pct_change_gdp'], sorted_data['pred_unemp_change_2'],
ax.scatter(sorted_data[=bmh_colors[1], label="Legge Di Okun")
color
# Titolo del grafico
f"EU, 2000-2024", loc='left')
ax.set_title(
# Etichette degli assi
'Variazione Del PIL')
ax.set_xlabel('Variazione Del Tasso Di Disoccupazione')
ax.set_ylabel(
# Aggiunta della griglia
True)
ax.grid(
# Aggiunta della legenda
ax.legend()
# Ottimizzazione del layout
plt.tight_layout()